--[[    
    Paranoia Enemy Player Alert
    Copyright (C) 2008 Victor Barrancos
  
    This file is part of Paranoia Enemy Player Alert.

    Paranoia Enemy Player Alert is free software: you can redistribute it 
    and/or modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation, either version 3 of the 
    License, or (at your option) any later version.

    Paranoia Enemy Player Alert is distributed in the hope that it will 
    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Paranoia Enemy Player Alert.  If not, see 
    <http://www.gnu.org/licenses/>.
]]--

Paranoia = CreateFrame("Frame", "PEPAFrame")
Paranoia:SetScript("OnEvent", function() Paranoia:OnEvent(event); end);

Paranoia.LastOnUpdate = 0;
Paranoia.Enabled = true; --not to be mistaken with ParanoiaData.Config.Enabled. Paranoia can be temporarily disabled if we are in a blacklisted zone.
Paranoia.Hidden = false; --likewise, paranoia can be hidden without being disabled.
Paranoia.FramesWaitingToClose = {};

ParanoiaData = {}
ParanoiaData.DB = {}
ParanoiaData.Config = {}

local Paranoia = Paranoia;

PEPA_MAJOR = "Paranoia Enemy Player Alert 2.0"
PEPA_MINOR = "(r"..tonumber(("$Revision: 19 $"):match("(%d+)"))..")"
PEPA_COMMVERSION = 1
PEPA_DATAVERSION = 1
PEPA_HOSTILEUNITFLAG = 0x548
PEPA_UPDATEINTERVAL = 0.05

--[[
Initialization/Global stuff
]]--

function Paranoia:OnLoad()
  Paranoia:RegisterEvent("VARIABLES_LOADED")
  Paranoia:RegisterEvent("PLAYER_ENTERING_WORLD")
end

function Paranoia:Initialize(self)
  SLASH_PARANOIACONF1 = "/paranoia";
  SLASH_PARANOIACONF2 = "/para";
  SLASH_PARANOIACONF3 = "/pepa";
  SlashCmdList["PARANOIACONF"] = function(msg) Paranoia:SlashHandler(msg); end
  SLASH_PARANOIARL1 = "/rl"
  SlashCmdList["PARANOIARL"] = function(msg) ReloadUI(); end
  Paranoia.Realm = GetRealmName()
  
  local englishFaction, localizedFaction = UnitFactionGroup("player")
  if (englishFaction == "Horde") then 
    Paranoia.OppFaction = FACTION_ALLIANCE
    Paranoia.OppFactionEng = "Alliance"
  else
    Paranoia.OppFaction = FACTION_HORDE
    Paranoia.OppFactionEng = "Horde"
  end
  
  Paranoia.Config.VerifyConfig(false)
  
  if ParanoiaData.DB == nil then Paranoia:CreateDefaultDB(); end
  if ParanoiaData.DB.DBVersion ~= PEPA_DATAVERSION then
    Paranoia:Msg("IMPORTANT: Your current database in incompatible with this version of Paranoia. The database has been reset.")
    Paranoia:CreateDefaultDB();
  end
  if not ParanoiaData.DB.Players[Paranoia.Realm] then
    Paranoia:CreateNewRealm(Paranoia.Realm);
  end
  
  Paranoia.List.ActiveList = Paranoia_EnemyList;
  Paranoia.List.Enable();
  
  if ParanoiaData.Config.Enabled then
    Paranoia.List.ShowList();
  else
    Paranoia.List.Disable();
  end
  
  if ParanoiaData.Config.Locked then
    Paranoia.List.SetLock(true)
  else
    Paranoia.List.SetLock(false)
  end
  
  Paranoia.List.InitializeButtons();
  Paranoia.List.InitializeButtonsCombat();
  
  Paranoia_WarnPopup:SetAlpha(ParanoiaData.Config.WarnPopupAlpha)
    
  Paranoia.Config.InitBlizzOptions()
  Paranoia.MinimapButton_Reposition();
  
  Paranoia:SetScript("OnUpdate", function() Paranoia:Update(self, arg1); end);
  
  DEFAULT_CHAT_FRAME:AddMessage(string.format("|cFF82C9B8"..PARANOIA_CHATPARALOADED, PEPA_MAJOR.." "..PEPA_MINOR, "|r|cFF9482CALifetapt|r|cFF82C9B8"));
  if (GetLocale() ~= "enUS" and GetLocale() ~= "enGB") and PARANOIA_CHATLOCALIZEDBY then
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8"..PARANOIA_CHATLOCALIZEDBY);
  end
end

function Paranoia:RegisterEvents()
  Paranoia:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
  Paranoia:RegisterEvent("ZONE_CHANGED")
  Paranoia:RegisterEvent("ZONE_CHANGED_NEW_AREA")
  Paranoia:RegisterEvent("PLAYER_REGEN_DISABLED")
  Paranoia:RegisterEvent("PLAYER_REGEN_ENABLED")
  Paranoia:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
  Paranoia:RegisterEvent("PLAYER_TARGET_CHANGED")
  Paranoia:RegisterEvent("CHAT_MSG_ADDON")
  Paranoia:RegisterEvent("PLAYER_DEAD")
  Paranoia:RegisterEvent("DUEL_REQUESTED")
end

function Paranoia:UnregisterEvents()
  Paranoia:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
  Paranoia:UnregisterEvent("ZONE_CHANGED")
  Paranoia:UnregisterEvent("ZONE_CHANGED_NEW_AREA")
  Paranoia:UnregisterEvent("PLAYER_REGEN_DISABLED")
  Paranoia:UnregisterEvent("PLAYER_REGEN_ENABLED")
  Paranoia:UnregisterEvent("UPDATE_MOUSEOVER_UNIT")
  Paranoia:UnregisterEvent("PLAYER_TARGET_CHANGED")
  Paranoia:UnregisterEvent("CHAT_MSG_ADDON")
  Paranoia:UnregisterEvent("PLAYER_DEAD")
  Paranoia:UnregisterEvent("DUEL_REQUESTED")
end

function Paranoia:OnEvent(event)
  if event == "VARIABLES_LOADED" then
    Paranoia:Initialize();
  elseif event == "PLAYER_ENTERING_WORLD" then
    Paranoia:ClearTemporaryUnits();
    if Paranoia:IsPlayerInInstance() then Paranoia:HideList(true); Paranoia:Msg(PARANOIA_CHATINSTANCE); end
  elseif event == "COMBAT_LOG_EVENT_UNFILTERED" then
    Paranoia.List.ScanCombatEvent(arg2, arg4, arg5, arg7, arg8, arg9, arg10); --event, sourcename, sourceflags, destname, destflags, spellid, spellname
  elseif event == "UPDATE_MOUSEOVER_UNIT" then
    Paranoia.List.ScanMouseoverTarget("mouseover");
  elseif event == "PLAYER_TARGET_CHANGED" then
    Paranoia.List.ScanMouseoverTarget("target");
  elseif event == "PLAYER_REGEN_DISABLED" then
    Paranoia.List.EnteringCombat()
  elseif event == "PLAYER_REGEN_ENABLED" then
    Paranoia.List.LeavingCombat()
  elseif event == "DUEL_REQUESTED" then
    Paranoia.List.AddToIgnore(arg1);
  elseif event == "PLAYER_DEAD" then
    if Paranoia.List.LastDamager then
      Paranoia:IncrementDeath(Paranoia.List.LastDamager);
      StaticPopupDialogs["PARANOIAKILLED"].text = "You were killed by "..Paranoia.List.LastDamager..". Do you wish to flag this player as KoS? (Dismissing in 10 seconds)";
      StaticPopupDialogs["PARANOIAKILLED"].OnAccept = function()
        Paranoia:SetPlayerKoS(Paranoia.List.LastDamager, true);
      end;
      if not Paranoia:GetPlayerKoS(Paranoia.List.LastDamager) then StaticPopup_Show("PARANOIAKILLED"); end
    end
  end
end

function Paranoia:Update(self, elapsed)
  Paranoia.LastOnUpdate = Paranoia.LastOnUpdate + elapsed
  if Paranoia.LastOnUpdate < PEPA_UPDATEINTERVAL then return; else Paranoia.LastOnUpdate = 0; end
  
  Paranoia.List.UpdateHostileList();
  Paranoia.List.UpdateVisibility();
  for k,v in pairs(Paranoia.FramesWaitingToClose) do
    if GetTime() - v > 0.4 and Paranoia.Hidden then
      getglobal(k):Hide();
      Paranoia.FramesWaitingToClose[k] = nil;
    end
  end
end

function Paranoia:BeginFrameDrag(self)
  if ParanoiaData.Config.Locked then return; end
  UIFrameFadeOut(self, 0.3, ParanoiaData.Config.FrameOpacity, 0.5);
  self:StartMoving(); 
end

function Paranoia:EndFrameDrag(self)
  if ParanoiaData.Config.Locked then return; end
  if Paranoia:Round(self:GetAlpha(), 2) ~= ParanoiaData.Config.FrameOpacity then UIFrameFadeIn(self, 0.3, 0.5, ParanoiaData.Config.FrameOpacity); end
  self:StopMovingOrSizing();
end

function Paranoia:Msg(msg)
  DEFAULT_CHAT_FRAME:AddMessage("|cFF8294C9Paranoia:|r |cFF82C9B8"..tostring(msg).."|r");
end

function Paranoia:DMsg(msg)
  if Paranoia.DebugEnabled then DEFAULT_CHAT_FRAME:AddMessage("|cFF9482CAPEPADebug:|r |cFF8294C9"..tostring(msg).."|r"); end
end

--[[
Slash Commands
]]--

--The functions below for parsing slash command arguments were written by Tigerheart from WoWI.
function Paranoia:GetArgument(msg)
 	if msg then
 		local a,b=strfind(msg, "(%S+)");
 		if a then
 			return strsub(msg,1,a-1), strsub(msg, b+1);
 		else	
 			return "";
 		end
 	end
end

function Paranoia:GetCmd(msg)
  if msg then
 		local a,b,c=strfind(msg, "(%S+)"); 
 		if a then
 			return c, strsub(msg, b+2);
 		else	
 			return "";
 		end
 	end
end

function Paranoia:SlashHandler(arg)
  local cmd, subCmd = Paranoia:GetCmd(arg);
  if arg then
    if arg ~= "testwarn" then arg = string.lower(arg); end
  end
  if (cmd == PARANOIA_SLACONFIG) then --config
    Paranoia.Config.ShowConfig();
  elseif (cmd == PARANOIA_SLAENABLE) then--enable
    ParanoiaData.Config.Enabled = true;
    Paranoia:Msg(PARANOIA_CHATENABLED);
  elseif (cmd == PARANOIA_SLADISABLE) then --disable
    ParanoiaData.Config.Enabled = false;
    Paranoia:Msg(PARANOIA_CHATDISABLED);
  elseif (cmd == "debug") then
    if (Paranoia.DebugEnabled) then 
      Paranoia.DebugEnabled = false;
      Paranoia.VerboseEnabled = false;
      Paranoia:Msg(PARANOIA_CHATDEBUGDISABLED);
    else
      Paranoia.DebugEnabled = true;
      Paranoia:Msg(PARANOIA_CHATDEBUGENABLED);
    end
  elseif (cmd == "verbose") then
    if (Paranoia.VerboseEnabled) then 
      Paranoia.VerboseEnabled = false;
      Paranoia:Msg("Verbose debug mode disabled.");
    else
      Paranoia.VerboseEnabled = true;
      Paranoia.DebugEnabled = true;
      Paranoia:Msg("Verbose debug mode enabled.");
    end
  elseif (cmd == "debuglist") then    -- not included in localization
    Paranoia:Msg("Debug Command List");
    DEFAULT_CHAT_FRAME:AddMessage("------------------------------------");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia testwarn [name] [class] [level]|r\nSimulates a test hostile player. With no arguments, uses Testplayer1-10. ");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/rl|r\nReloads the user interface. ");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia clear|r\nResets timeouts, clears the enemy/ignore lists, and unloads the SpellList.");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia cleardb|r\nClears the entire enemy database (reloads UI).");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia clearrealm|r\nClears the enemy database for this realm only.");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia verbose|r\nToggles verbose debug mode (displays data about all incoming combatlog events).");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia gc|r\nForces a garbage collection.");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia mem|r\nDisplays Paranoia's memory usage.");
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia frame|r\nReturns whether or not the secure or nonsecure enemy list is active.");
    if GetLocale() ~= "enUS" and GetLocale() ~= "enGB" then DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia ping [party|guild|player] [playername]|r\nLooks for other players using Paranoia."); end
  elseif (cmd == "testwarn") then
    local testName, testInfo = Paranoia:GetCmd(subCmd);
    if testName == "" then
      Paranoia:Msg("Calling ProcessHostile (using Testplayer1-11)");
      Paranoia.List.ProcessHostile("Testplayer", "DRUID", 0, false, -1);
      Paranoia.List.ProcessHostile("Testplayer2", "MAGE",10, false, -1);
      Paranoia.List.ProcessHostile("Testplayer3", "PALADIN", 20, true, -1);
      Paranoia.List.ProcessHostile("Testplayer4", "ROGUE", 30, false, -1);
      Paranoia.List.ProcessHostile("Testplayer5", "SHAMAN", 40, true, -1);
      Paranoia.List.ProcessHostile("Testplayer6", "WARLOCK", 50, true, -1);
      Paranoia.List.ProcessHostile("Testplayer7", "WARRIOR", 60, false, -1);
      Paranoia.List.ProcessHostile("Testplayer8", "PRIEST", 70, true, -1);
      Paranoia.List.ProcessHostile("Testplayer9", "HUNTER", 80, false, -1);
      Paranoia.List.ProcessHostile("Testplayer10", "DEATHKNIGHT", math.random(1,80), true, -1);
      Paranoia.List.ProcessHostile("Testplayer11", "UNKNOWN", math.random(1,80), false, -1);
    elseif testName ~= "" then
      local testClass, testLevel = Paranoia:GetCmd(testInfo);
      Paranoia:Msg("Calling ProcessHostile (using "..testName..")");
      Paranoia.List.ProcessHostile(testName, tostring(string.upper(testClass)), tonumber(testLevel), false, -1);
    end
  elseif (cmd == "rui") then
    ReloadUI()
  elseif (cmd == "clear") then
    Paranoia_SpellList = nil;
    Paranoia.List.ActiveHostiles = {};
    Paranoia.List.IgnoreList = {};
    Paranoia.List.LastWarning = 0;
    Paranoia.List.LastKoSWarning = 0;
    Paranoia:Msg("Enemy player table cleared.");
  elseif (cmd == "cleardb") then
    Paranoia:CreateDefaultDB();
    ReloadUI();
  elseif (cmd == "clearrealm") then
    Paranoia:CreateNewRealm(GetRealmName());
    Paranoia:Msg("Data for this realm has been cleared.");
  elseif (cmd == "gc") then
    local beforeMem = 0;
    local afterMem = 0;
    UpdateAddOnMemoryUsage();
    beforeMem = Paranoia:Round(GetAddOnMemoryUsage("Paranoia_EPA"),2)
    Paranoia:Msg("Forcing garbage collection...");
    collectgarbage();
    UpdateAddOnMemoryUsage();
    afterMem = Paranoia:Round(GetAddOnMemoryUsage("Paranoia_EPA"),2)
    Paranoia:Msg("Garbage collection finished.\nBefore: "..beforeMem.."kb\nAfter: "..afterMem.."kb");
  elseif (cmd == "mem") then
    UpdateAddOnMemoryUsage();
    Paranoia:Msg("Using "..Paranoia:Round(GetAddOnMemoryUsage("Paranoia_EPA"),2).."kb of memory... type /para gc for garbage collection.");
  elseif (cmd == "frame") then
    Paranoia:Msg("Paranoia.List.ActiveList is set to: "..Paranoia.List.ActiveList:GetName());
    if Paranoia_EnemyList:IsVisible() then Paranoia:Msg("Paranoia_EnemyList is currently visible."); end
    if Paranoia_EnemyListCombat:IsVisible() then Paranoia:Msg("Paranoia_EnemyListCombat is currently visible."); end
  elseif cmd == "ping" then
    if isPingWaiting then
      Paranoia:Msg("Paranoia is waiting for a reply for a previous ping... please wait.");
      return;
    end
    local pingCmd, pingTarget = Paranoia:GetCmd(subCmd);
    if pingCmd == "party" then
      if GetNumPartyMembers() == 0 then
        Paranoia:Msg("You are not in a party.");
        return;
      end
      Paranoia:Msg("Pinging party members, please wait a moment...");
      Paranoia:commMsg("PING", UnitName("player"), "PARTY", "ALERT");
      gotFirstReply = false;
      lastReplyTime = GetTime();
      isPingWaiting = true;
    elseif pingCmd == "guild" then
      if IsInGuild() == nil then
        Paranoia:Msg("You are not in a guild.")
        return;
      end
      Paranoia:Msg("Pinging guild members, please wait a moment...");
      Paranoia:commMsg("PING", UnitName("player"), "GUILD", "ALERT");
      gotFirstReply = false;
      lastReplyTime = GetTime();
      isPingWaiting = true;
    elseif pingCmd == "player" then
      if pingTarget == "" then
        Paranoia:Msg("You must specify a player.");
        return;
      end
      if strlower(pingTarget) == strlower(UnitName("player")) then
        Paranoia:Msg(UnitName("player").." is almost certainly using Paranoia.");
        return;
      end
      Paranoia:Msg("Pinging player, please wait a moment...");
      Paranoia:commMsg("PING", UnitName("player"), "WHISPER", "ALERT", pingTarget);
      gotFirstReply = false;
      lastReplyTime = GetTime();
      isPingWaiting = true;
    else
      Paranoia:Msg("You must specify party, guild, or player.");
    end
  elseif cmd == nil or cmd == "" then
    Paranoia:Msg(PARANOIA_CHATSLASHLIST);
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8"..PARANOIA_CHATSLASHLISTCONFIG);
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8"..PARANOIA_CHATSLASHLISTENABLE);
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8"..PARANOIA_CHATSLASHLISTDISABLE);
    if GetLocale() == "enUS" or GetLocale() == "enGB" then DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8/paranoia ping [party|guild|player] [playername]|r\nLooks for other players using Paranoia."); end
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8"..PARANOIA_CHATSLASHLISTDEBUG);
    DEFAULT_CHAT_FRAME:AddMessage("|cFF82C9B8"..PARANOIA_CHATSLASHLISTDEBUGL);
  else
    Paranoia:Msg(string.format(PARANOIA_CHATUNRECOGNIZED, cmd));
  end
  
end

--[[
Database Functions
]]--

function Paranoia:CreateDefaultDB()
  ParanoiaData.DB = {
    DBVersion = PEPA_DATAVERSION,
    Players = {},
  };
end

function Paranoia:CreateNewRealm(realmName)
  ParanoiaData.DB.Players[realmName] = {
    Horde = {
    },
    Alliance = {
    },
    TotalKills = 0,
    TotalDeaths = 0,
  };
end

function Paranoia:CreateNewPlayer(name, level, class, guild, lastSeen, kos, temp)
  if Paranoia:IsPlayerInBG() then temp = true; end
  if Paranoia:IsPlayerInArena() then temp = true; end
  if Paranoia:IsPlayerInFFA() then temp = true; end
  
  if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] ~= nil then error("CreateNewPlayer: Player "..name.." already exists in database."); end
  
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] = {};
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][1] = level;         --integer
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][2] = class;         --integer
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][3] = guild;         --string
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][4] = lastSeen;      --integer
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5] = kos;           --bool
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][6] = 0;             --integer (kills)
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][7] = 0;             --integer (deaths)
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][8] = "";            --string (player note)
  if temp then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][9] = true; end
end

function Paranoia:PlayerExists(name)
  if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] ~= nil then return true; else return false; end
end

function Paranoia:UpdatePlayer(name, level, class, guild, lastSeen, kos, kills, deaths, note)
  if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] ~= nil then
    if level then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][1] = level; end
    if class then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][2] = class; end
    if guild then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][3] = guild; end
    if lastSeen then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][4] = lastSeen; end
    if kos ~= nil then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5] = kos; end
    if kills then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][6] = kills; end
    if deaths then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][7] = deaths; end
    if note then ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][8] = note; end
  end
end

function Paranoia:IncrementKill(name)
  if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] ~= nil then
    ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][6] = ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][6] + 1;
    ParanoiaData.DB.Players[Paranoia.Realm].TotalKills = ParanoiaData.DB.Players[Paranoia.Realm].TotalKills + 1;
  end
end

function Paranoia:IncrementDeath(name)
  if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] ~= nil then
    ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][7] = ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][7] + 1;
    ParanoiaData.DB.Players[Paranoia.Realm].TotalDeaths = ParanoiaData.DB.Players[Paranoia.Realm].TotalDeaths + 1;
  end
end

function Paranoia:SetPlayerKoS(name, isKoS)
  if isKoS == true then
    if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5] == true then return; end
    ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5] = true;
    Paranoia:Msg(name.." is now flagged as Kill-on-Sight.");
  else
    if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5] == false then return; end
    ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5] = false;
    Paranoia:Msg(name.." is no longer flagged as Kill-on-Sight.");
  end
end

function Paranoia:GetPlayerClassLevelGuild(name)
  return ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][2], ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][1], ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][3];
end

function Paranoia:GetPlayerKoS(name)
  return ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][5];
end

function Paranoia:ClearTemporaryUnits()
  if ParanoiaData.DB.Players[Paranoia.Realm] == nil then return; end
  for name, _ in pairs(ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng]) do
    if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name][9] ~= nil then
      Paranoia:DeletePlayer(name);
    end
  end
end

function Paranoia:DeletePlayer(name) 
  if ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] == nil then error("DeletePlayer: Player "..name.." doesn't exist in database."); end
  
  ParanoiaData.DB.Players[Paranoia.Realm][Paranoia.OppFactionEng][name] = nil;
end

--[[
Utility Functions
]]--

function Paranoia:Round(value, decimalplaces)
  local mult = 10^(decimalplaces or 0)
  return math.floor(value * mult + 0.5) / mult
end

function Paranoia:ToBoolean(value)
  if value == 1 then return(true); end
  if value == nil then return(false); end
  if type(value) == "boolean" then return(value); end
end

function Paranoia:IsGuildieNearby(name)
  GuildRoster();
  for i = 1, (GetNumGuildMembers(true)) do
    local gname, _, _, _, _, gzone, _, _, _, _ = GetGuildRosterInfo(i)
    if gname == name then 
      if gzone ~= GetZoneText() then return(false); end
      return(true);
    end
  end
  return(false);
end

function Paranoia:IsPlayerInArena()
  if (IsActiveBattlefieldArena()) then
    return(true);
  end
  return(false);
end

function Paranoia:IsPlayerInBG()
  local inInstance, instanceType = IsInInstance()
  if inInstance ~= nil and instanceType == "pvp" then return(true); else return(false); end
  return(false);
end

function Paranoia:IsPlayerInFFA()
    local isFFA = UnitIsPVPFreeForAll("player")
    if isFFA == nil then isFFA = false; end
    return isFFA;
end

function Paranoia:IsPlayerInInstance()
  local inInstance, instanceType = IsInInstance()
  if inInstance ~= nil and (instanceType == "party" or instanceType == "raid") then return(true); else return(false); end
  return(false);  
end


function Paranoia:IsPlayerInSanctuary()
    local pvpType, isFFA, faction = GetZonePVPInfo();
    isFFA = nil;
    faction = nil;
    if (pvpType == "sanctuary") then
        return(true);
    else
        return(false);
    end
end

function Paranoia:LocalizeClass(class)  --takes english class, allcaps, no spaces, returns localized string as per localization file
  class = string.upper(class)
  if class == "DEATHKNIGHT" then return PARANOIA_DEATHKNIGHT; end
  if class == "DRUID" then return PARANOIA_DRUID; end
  if class == "HUNTER" then return PARANOIA_HUNTER; end
  if class == "MAGE" then return PARANOIA_MAGE; end
  if class == "ROGUE" then return PARANOIA_ROGUE; end
  if class == "PALADIN" then return PARANOIA_PALADIN; end
  if class == "PRIEST" then return PARANOIA_PRIEST; end
  if class == "SHAMAN" then return PARANOIA_SHAMAN; end
  if class == "WARLOCK" then return PARANOIA_WARLOCK; end
  if class == "WARRIOR" then return PARANOIA_WARRIOR; end
  return UNKNOWN
end

--[[
Miscellaneous Functions
]]--

function Paranoia:TestWarnPopup()
  Paranoia_WarnPopup:Clear();
  Paranoia_WarnPopup:SetTimeVisible(ParanoiaData.Config.WarnPopupDisplayDuration);
  Paranoia_WarnPopup:SetFadeDuration(ParanoiaData.Config.WarnPopupFadeDuration);
  Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_ALERTTEST, Paranoia.OppFaction), 255, 0, 0 ,100)
end

--[[
Minimap Functions (Using Gello's minimap button template)
]]--

function Paranoia:MinimapButton_Reposition()
	Paranoia_MinimapButton:SetPoint("TOPLEFT","Minimap","TOPLEFT",52-(80*cos(ParanoiaData.Config.MinimapPos)),(80*sin(ParanoiaData.Config.MinimapPos))-52)
end


function Paranoia:MinimapButtonDraggingFrame_OnUpdate()

	local xpos,ypos = GetCursorPosition()
	local xmin,ymin = Minimap:GetLeft(), Minimap:GetBottom()

	xpos = xmin-xpos/UIParent:GetScale()+70 -- get coordinates as differences from the center of the minimap
	ypos = ypos/UIParent:GetScale()-ymin-70
  
	ParanoiaData.Config.MinimapPos = math.deg(math.atan2(ypos,xpos)) -- save the degrees we are relative to the minimap center
	Paranoia:MinimapButton_Reposition() -- move the button
end

function Paranoia:MinimapButton_OnClick()
	if arg1 == "LeftButton" then
    if ParanoiaData.Config.Enabled == false then
      ParanoiaData.Config.Enabled = true;
      Paranoia:Msg(PARANOIA_CHATENABLED);
    else
      ParanoiaData.Config.Enabled = false;
      Paranoia:Msg(PARANOIA_CHATDISABLED);
    end
  else
    Paranoia.Config.ShowConfig();
  end
end

function Paranoia:UpdateMinimapVisibility()
  if ParanoiaData.Config.HideMinimap == true then
    Paranoia_MinimapButton:Hide();
  else
    Paranoia_MinimapButton:Show();
  end
end